
package com.tools.cleanmaster.functionpage;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Shader;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.RelativeLayout;

import com.tools.cleanmaster.R;
import com.tools.cleanmaster.utils.CompatibilityHelper;

import java.util.Arrays;

/**
 * cpu降温背景线性渐变
 */
public class BgColorGradientView extends RelativeLayout {
    private Context mContext;

    public interface BgColorGradientListener {
        void onGradientStart();

        void onGradientEnd();
    }

    public enum GradientColorType {
        BLUE, GREEN, YELLOW, ORANGE, RED, NORMAL
    }

    private static final long GRADIENT_ANIM_TIME = 2000;

    // 颜色数组
    public static final int[] COLOR_BLUES = new int[]{
            0xff04e2b2, 0xff24c4f8
    };
    public static final int[] COLOR_GREEN = new int[]{
            0xFF42C477, 0xFF42DA88
    };
    public static final int[] COLOR_YELLOW = new int[]{
            0xFF12B8B4, 0xFF02D9CB
    };
    public static final int[] COLOR_ORANGES = new int[]{
            0xFFFB6144, 0xFFF7B063
    };
    public static final int[] COLOR_REDS = CompatibilityHelper.isSamsungPhone() ? new int[]{
            0xFFEF6474, 0xFFFB8061
    } : new int[]{0xFFF7596B, 0xFFF78163};

    // 颜色对应的位置数组
    private static final float[] COLOR_LOCATIONS = new float[]{
            0, 0.8f
    };

    private int[] mStartColors = COLOR_BLUES;
    private int[] mCurrentColors = COLOR_BLUES;
    private int[] mToColors = COLOR_BLUES;

    private long mAnimDuration = GRADIENT_ANIM_TIME;
    private int mTotalWidth;
    private int mTotalHeight;
    private int mHalfWidth;
    private Paint mBackPaint;
    private Paint mLightGradientPaint;
    private PaintFlagsDrawFilter mDrawFilter;

    private Interpolator mInterpolator;
    private BgColorGradientListener mGradientListener;
    private LinearGradient mLinearGradient;
    private ValueAnimator valueAnimator;
    // 是否正在进行变色
    private boolean mIsChanging;
    private static final int MSG_UPDATE = 0;
    // 颜色动态设置开始时间
    private long mStartTime = 0;
    // 颜色动态总时间
    private static final int TIME_TOTAL = 1200;

    // 刷新颜色的间隔
    private int[] mCurrentStartColor = COLOR_BLUES;
    private int[] minValues = new int[]{Integer.MIN_VALUE, Integer.MIN_VALUE};
    private int[] mNewEndColor = new int[]{Integer.MIN_VALUE, Integer.MIN_VALUE};
    private int[] mCurrentEndColor = new int[]{Integer.MIN_VALUE, Integer.MIN_VALUE};
    protected static final long TIME_DELAY = 20;

    @SuppressLint("HandlerLeak")
    private Handler mHander = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_UPDATE:
                    // 用mCurrentProgress判断来判断是否结束
                    long now = System.currentTimeMillis();
                    if (now < mStartTime + TIME_TOTAL) {
                        mCurrentColors = transformColors(mCurrentStartColor,
                                mCurrentEndColor, (float) (now - mStartTime) / TIME_TOTAL);
                        BgColorGradientView.this.postInvalidate();
                        mHander.sendEmptyMessageDelayed(MSG_UPDATE, TIME_DELAY);
                    } else {
                        mCurrentStartColor = Arrays.copyOf(mCurrentEndColor, 2);
                        // 如果有mNewEndColor且不同的END,则开始新一轮；否则结束
                        if (!Arrays.equals(mNewEndColor, minValues)) {
                            if (Arrays.equals(mNewEndColor, mCurrentEndColor)) {
                                mNewEndColor = Arrays.copyOf(minValues, 2);
                                mCurrentEndColor = Arrays.copyOf(minValues, 2);
                            } else {
                                mCurrentEndColor = Arrays.copyOf(minValues, 2);
                                setColor(mNewEndColor);
                                mNewEndColor = Arrays.copyOf(minValues, 2);
                            }
                        } else {
                            mCurrentEndColor = Arrays.copyOf(minValues, 2);
                        }
                    }
                    break;

                default:
                    break;
            }
        }
    };

    public BgColorGradientView(Context context) {
        super(context);
        this.mContext = context;
        init();
    }

    public BgColorGradientView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        init();
    }

    public BgColorGradientView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public BgColorGradientView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        this.mContext = context;
        init();
    }

    private void init() {
        initPaint();
        mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mInterpolator = new LinearInterpolator();
        setWillNotDraw(false);

        Resources resource = getResources();
        Resources.Theme theme = getContext().getTheme();

        int[] defaultColor = getColorArray(resource, theme, R.color.func_page_bg_start_1, R.color.func_page_bg_end_1);

        mStartColors = defaultColor;
        mToColors = defaultColor;
        mCurrentColors = defaultColor;
    }

    private void setColor(int[] color) {
        if (!Arrays.equals(mCurrentStartColor, color)) {
            // 判断是否在动态改变：如果不是，则开始；如果已经是：则只设置mNewEndColor
            if (Arrays.equals(mCurrentEndColor, minValues)) {
                mStartTime = System.currentTimeMillis();
                mCurrentEndColor = Arrays.copyOf(color, 2);
                mNewEndColor = Arrays.copyOf(minValues, 2);
                mHander.sendEmptyMessage(MSG_UPDATE);
            } else {
                mNewEndColor = Arrays.copyOf(color, 2);
            }
        }
    }

    public void setColorType(GradientColorType type) {
        setColor(getColorWithType(type));
    }

    private void initPaint() {
        mBackPaint = new Paint();
        mBackPaint.setAntiAlias(true);
        mLightGradientPaint = new Paint();
        mLightGradientPaint.setAntiAlias(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.setDrawFilter(mDrawFilter);
        if (mTotalWidth == 0 || mTotalHeight == 0) {
            return;
        }

        mLinearGradient = new LinearGradient(0, 0,
                mHalfWidth, mTotalHeight, mCurrentColors, COLOR_LOCATIONS, Shader.TileMode.MIRROR);
        mLightGradientPaint.setShader(mLinearGradient);
        canvas.drawRect(0, 0, mTotalWidth, mTotalHeight, mLightGradientPaint);
    }

    public void setInterpolator(Interpolator interpolator) {
        this.mInterpolator = interpolator;
    }

    public void startGradient(GradientColorType colorType, long duration, BgColorGradientListener listener) {
        startGradient(getColorWithType(colorType), duration, listener);
    }

    public void startGradient(int[] toColors, long duration, BgColorGradientListener listener) {
        this.mToColors = toColors;
        this.mAnimDuration = duration;
        this.mGradientListener = listener;

        valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.setDuration(mAnimDuration);
        valueAnimator.setInterpolator(mInterpolator);
        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animator) {
                float animatedValue = (Float) animator.getAnimatedValue();
                mCurrentColors = transformColors(mStartColors, mToColors, animatedValue);
                BgColorGradientView.this.postInvalidate();
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                if (mGradientListener != null) {
                    mGradientListener.onGradientStart();
                }
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mIsChanging = false;
                mStartColors = mToColors;
                if (mGradientListener != null) {
                    mGradientListener.onGradientEnd();
                }
            }
        });
        valueAnimator.start();
    }

    public GradientColorType getColorBySize(long temp) {
        if (temp >= 40) {
            return GradientColorType.RED;
        } else if (temp >= 35) {
            return GradientColorType.ORANGE;
        } else if (temp >= 30) {
            return GradientColorType.YELLOW;
        } else if (temp >= 25) {
            return GradientColorType.GREEN;
        } else {
            return GradientColorType.BLUE;
        }
    }

    private int[] getColorWithType(GradientColorType colorType) {
        Resources resource = getResources();
        Resources.Theme theme = getContext().getTheme();

        int[] toColor = COLOR_BLUES;
        switch (colorType) {
            case BLUE:
                toColor = getColorArray(resource, theme, R.color.primary_color, R.color.primary_color);
                break;
            case ORANGE:
                toColor = COLOR_ORANGES;
                break;
            case RED:
                toColor = COLOR_REDS;
                break;
            case YELLOW:
                toColor = COLOR_YELLOW;
                break;
            case GREEN:
                toColor = COLOR_GREEN;
                break;
            case NORMAL:
                toColor = getColorArray(resource, theme, R.color.primary_color, R.color.primary_color);
            default:
                break;
        }
        return toColor;
    }

    private int[] getColorArray(Resources resource, Resources.Theme theme, int... resArray) {
        int[] array = new int[resArray.length];
        for (int index = 0; index < resArray.length; index++) {
            array[index] = getColor(resource, resArray[index], theme);
        }
        return array;
    }

    private int getColor(Resources resource, int resId, Resources.Theme theme) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return resource.getColor(resId, theme);
        } else {
            return resource.getColor(resId);
        }
    }

    private int[] transformColors(int[] startColors, int[] toColors, float fraction) {
        int[] currentColors = new int[2];
        for (int i = 0; i < startColors.length; i++) {
            currentColors[i] = transformColor(startColors[i], toColors[i], fraction);
        }
        return currentColors;
    }

    private int transformColor(int startColor, int toColor, float fraction) {
        int mStartAlpha = Color.alpha(startColor);
        int mStartRed = Color.red(startColor);
        int mStartGreen = Color.green(startColor);
        int mStartBlue = Color.blue(startColor);
        int mIntervalAlpha = Color.alpha(toColor) - mStartAlpha;
        int mIntervalRed = Color.red(toColor) - mStartRed;
        int mIntervalGreen = Color.green(toColor) - mStartGreen;
        int mIntervalBlue = Color.blue(toColor) - mStartBlue;
        int currentAlpha = (int) (mIntervalAlpha * fraction + mStartAlpha);
        int currentRed = (int) (mIntervalRed * fraction + mStartRed);
        int currentGreen = (int) (mIntervalGreen * fraction + mStartGreen);
        int currentBlue = (int) (mIntervalBlue * fraction + mStartBlue);
        return Color.argb(currentAlpha, currentRed, currentGreen, currentBlue);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mTotalWidth = w;
        mTotalHeight = h;
        if (mTotalWidth == 0 || mTotalHeight == 0) {
            return;
        }
        mHalfWidth = mTotalWidth / 2;
        mLinearGradient = new LinearGradient(mHalfWidth, 0,
                mHalfWidth, mTotalHeight, COLOR_BLUES, COLOR_LOCATIONS, Shader.TileMode.MIRROR);
        mLightGradientPaint.setShader(mLinearGradient);
    }
}
